package com.ou.csbs.capstone.tools;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;

import com.ou.csbs.capstone.models.AttributeModel;
import com.ou.csbs.capstone.models.RenderableModel;
import com.ou.csbs.capstone.models.shapes.Circle;
import com.ou.csbs.capstone.models.shapes.Line;
import com.ou.csbs.capstone.models.shapes.Text;
import com.ou.csbs.capstone.models.shapes.control.ControlPoint.ControlPointPlacemark;
import com.ou.csbs.capstone.models.shapes.control.ShapeControlList;
import com.ou.csbs.capstone.views.worldwind.WorldWindCanvas;

import gov.nasa.worldwind.event.SelectEvent;
import gov.nasa.worldwind.event.SelectListener;
import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.pick.PickedObjectList;
import gov.nasa.worldwind.render.Material;

/**
 * The Editing Tool for all drawn objects. This tool extends MouseAdapter to intercept mouse actions and implements both SelectListener to determine object picking and KeyListner to intercept DELETE key presses
 * for deleting objects. All objects are determined by their instantiated classes (Circle, Line, or Text).
 * 
 * To select an object, all one has to do is click on the desired object to edit. To de-select, click on terrain. To edit, either move a control point, or in the instance of a Circle, click the outer edge of the
 * Circle and drag. All other key presses or mouse clicks are handed back over to WorldWind for processing, so clicking and dragging terrain will not de-select the object and further editing can continue.
 * 
 * @author Senior Capstone
 */
public class EditingTool extends MouseAdapter implements SelectListener, KeyListener {
	private Object object;
	private RenderableModel model;
	private ShapeControlList scl;
	private boolean objectSelected;

	public EditingTool(RenderableModel model){
		this.model = model;
		this.scl = new ShapeControlList(this.model);
	}

	/*
	 * De-selecting objects
	 */
	@Override
	public void mouseClicked(MouseEvent mouseEvent){
		PickedObjectList objects = WorldWindCanvas.getWorldWindow().getObjectsAtCurrentPosition();
		if(object != null && objects != null && objects.getTopPickedObject() != null && objects.getTopPickedObject().isTerrain()){
			deselectObject();
			removeControlPoints();
			mouseEvent.consume();
		}
	}
	/*
	 * Intercepting DELETE key presses.
	 */
	@Override
	public void keyPressed(KeyEvent keyEvent) {
		if(keyEvent.getKeyCode() == KeyEvent.VK_DELETE && objectSelected){
			if(object instanceof Circle){
				((Circle) object).removeShape(this.model);
			}
			if(object instanceof Line){
				((Line) object).removeShape(this.model);
			}
			if(object instanceof Text){
				((Text) object).removeShape(this.model);
			}
			deselectObject();
			removeControlPoints();
			keyEvent.consume();
		}
	}
	
	@Override
	public void selected(SelectEvent selectEvent) {
		/*
		 * Select events
		 */
		if(selectEvent.getEventAction().equals(SelectEvent.LEFT_PRESS) &&
				selectEvent.hasObjects()){
			/*
			 * Selecting Surface Circle
			 */
			if(selectEvent.getTopObject() instanceof Circle){
				object = (Circle) selectEvent.getTopObject();
				objectSelected = true;
				scl.updateControlPoints((Position) ((Circle) object).getCenter());
				scl.drawControlPoints();
				AttributeModel.setAttributes(((Circle) object).getAttributes());
			}
			/*
			 * Selecting Surface Polyline
			 */
			if(selectEvent.getTopObject() instanceof Line){
				object = (Line) selectEvent.getTopObject();
				objectSelected = true;
				scl.updateControlPoints(((Line) object).getLocations());
				scl.drawControlPoints();
				AttributeModel.setAttributes(((Line) object).getAttributes());
			}
			/*
			 * Selecting Surface Text
			 */
			if(selectEvent.getTopObject() instanceof Text){
				object = (Text) selectEvent.getTopObject();
				objectSelected = true;
				scl.updateControlPoints(((Text) object).getPosition());
				scl.drawControlPoints();
				AttributeModel.setOutlineColor(new Material(((Text) object).getColor()));
				AttributeModel.setFontSize(((Text) object).getFontSize());
			}
		}

		/*
		 * Drag Events
		 */
		if(selectEvent.getEventAction().equals(SelectEvent.DRAG) &&
				selectEvent.hasObjects()){
			/*
			 * Circle instances
			 */
			if(object instanceof Circle){
				if(selectEvent.getTopObject() instanceof ControlPointPlacemark){
					Position position = WorldWindCanvas.getWorldWindow().getCurrentPosition();
					if(position != null){
						((Circle) object).setCenter(position);
						((ControlPointPlacemark) selectEvent.getTopObject()).setPosition(position);
					}
				}
				if(selectEvent.getTopObject() instanceof Circle){
					object = (Circle) selectEvent.getTopObject();
					Position position = WorldWindCanvas.getWorldWindow().getCurrentPosition();
					Position center = (Position) ((Circle) object).getCenter();
					if(position != null && center != null){
						((Circle) object).setRadius(Circle.calculateRadius(center, position));
					} 
				}
			}
			/*
			 * Line instances
			 */
			if(object instanceof Line){
				if(selectEvent.getTopObject() instanceof ControlPointPlacemark){
					for(int i = 0; i < scl.getControlPoints().size(); i++){
						if(scl.getControlPoints().get(i).getControlPointPlacemark() == selectEvent.getTopObject()){
							Position position = WorldWindCanvas.getWorldWindow().getCurrentPosition();
							if(position != null){
								@SuppressWarnings("unchecked")
								ArrayList<LatLon> positions = (ArrayList<LatLon>) ((Line) object).getLocations();
								positions.set(i, position);
								((Line) object).updatePoint(i, position);
								((ControlPointPlacemark) selectEvent.getTopObject()).setPosition(position);
							}
						}
					}
				}
			}
			/*
			 * Text instances
			 */
			//TODO
			if(object instanceof Text){
				if(selectEvent.getTopObject() instanceof ControlPointPlacemark){
					if(scl.getControlPoints().get(0).getControlPointPlacemark() == selectEvent.getTopObject()){
						Position position = WorldWindCanvas.getWorldWindow().getCurrentPosition();
						if(position != null){
							((Text) object).setPosition(position);
							((ControlPointPlacemark) selectEvent.getTopObject()).setPosition(position);
						}
					}
				}
			}
		}
		//must remove and redraw text to reapply the draw transformations and sector calculations after movement
		if(selectEvent.getEventAction().equals(SelectEvent.DRAG_END) &&
				selectEvent.hasObjects()){
			if(object instanceof Text){
				if(selectEvent.getTopObject() instanceof ControlPointPlacemark){
					if(scl.getControlPoints().get(0).getControlPointPlacemark() == selectEvent.getTopObject()){
						Position position = WorldWindCanvas.getWorldWindow().getCurrentPosition();
						if(position != null){
							((Text) object).removeShape(this.model);
							Text newText = new Text(((Text) object).getText().toString(), 
									((Text) object).getPosition(), 
									((Text) object).getAngle(), 
									((Text) object).getTextSize(), 
									((Text) object).getFontSize(),
									((Text) object).getColor());
							newText.drawShape(this.model);
							object = newText;
							scl.updateControlPoints(newText.getPosition());
							scl.drawControlPoints();
						}
					}
				}
			}
		}
		WorldWindCanvas.getWorldWindow().redrawNow();
		selectEvent.consume();
	}

	public void removeControlPoints(){
		scl.removeControlPoints();
	}

	public boolean isObjectSelected() {
		return objectSelected;
	}
	public Object getSelectedObject(){
		return object;
	}
	public void deselectObject(){
		object = null;
		objectSelected = false;
	}
	
	/*
	 * Ignored events
	 */
	@Override
	public void keyReleased(KeyEvent keyEvent) {
	}
	@Override
	public void keyTyped(KeyEvent paramKeyEvent) {	
	}
}
